local base = game_mode.base
local mode = class("net_game",base)
mode.mapBuff = {}
mode.aiBuff = {}
local f = io.open(BASEPATH.."res/tank.ai","r")
local aiString = f:read("*a")
f:close()
mode.defaultAI = aiString
mode.roomMax = 20
mode.roomMin = 1
mode.gameLast = 60*3
mode.mapName = "hunter"
mode.teamCount = 20
mode.itemGenCD = 30
mode.itemGenTypes = {1,2,3,4,5,6,7}
mode.npcGenCD = 5
mode.npcGenTypes = {1,2,3,4,5,6,7,8}
mode.npcGenCollCheck = true
mode.enablePlayerRebirth = true
mode.playerRebirthCD = 5
mode.playerBirthCollCheck = true
mode.playerGenTypes = {1,2,3,4,5,6,7,8}

function mode:init(room)
    base.init(self)
    self.netID = 0
    self.room = room
    self.roomID =room.id
    self.players = self.room.players
    self.state = "wait" --run destroyed 几种状态
    self.gameTimer = self.roomLast
    self:setMap(self.mapName)
    self:initItemGen()
    self:initNPCGen()
    self:initTeams()
    self:onInit()
end


function mode:update(dt)
    base.update(self,dt)
    if self.state == "run" then
        self:updateGameTime(dt)
        self:updateItemGen(dt)
        self:updateNPCGen(dt)
        self:onUpdate(dt)
    end
end

function mode:newNetID()
    self.netID = self.netID + 1
    return self.netID
end

function mode:setNetObj(obj)
    obj:setID(self:newNetID())
    if self.room and self.state == "run" then
        net:sendToRoom(self.room,"create_obj",obj:getData())
    end
end



function mode:initTeams()
    self.teams = {}
    for i = 1,self.teamCount do
        self.teams[i] = {}
    end
end

function mode:setMap(name)
    Map(self,1,16,16)
    if name == "random" then
        self.map:random(self.mapW,self.mapH)
        return 
    end
    if not mode.mapBuff[name] then 
        local f = io.open("client/res/"..name..".dat")
        local map_dat = bitser.loads(f:read("*a"))
        f:close()
        mode.mapBuff[name] = map_dat
    end
    self.map:setData(mode.mapBuff[name])
end

function mode:loadAI(name)
    if not mode.aiBuff[name] then
        local f = io.open("client/res/"..name..".ai","r")
        local aiString = f:read("*a")
        f:close()
        mode.aiBuff[name] = aiString
    end
    return mode.aiBuff[name]
end

function mode:initItemGen(timeCD,types)
    if self.itemGenCD <= 0 then return end
    self.enableItemGen = true
   	self.itemGenTimer = self.itemGenCD
end

function mode:updateItemGen(dt)
    if not self.enableItemGen then return end
    self.itemGenTimer = self.itemGenTimer - dt
	if self.itemGenTimer<0 then
		self.itemGenTimer = self.itemGenCD
		local item = Item(
            self,
			math.random(1,self.map.w*16),
			math.random(1,self.map.h*16),
			2,
			self.itemGenTypes[math.random(1,#self.itemGenTypes)]
		)
		self:setNetObj(item)
	end
end

function mode:initNPCGen(minX,maxX,minY,maxY)
    if self.npcGenCD <= 0 then return end
    self.enableNPCGen = true
    self.npcGenTimer = self.npcGenCD
end

function mode:setNPCGenPos(minX,maxX,minY,maxY)
    self.npcGenPos = {minX = minX,maxX = maxX,
        minY = minY,maxY = maxY}
end

function mode:setNPCAI(aiString)
    self.npcAI = aiString
end

function mode:updateNPCGen(dt)
    if not self.enableNPCGen then return end
    self.npcGenTimer = self.npcGenTimer - dt
	if self.npcGenTimer<0 then
		self.npcGenTimer = self.npcGenCD
		local tank = self:newTank(
            0,
            self.npcGenTypes[math.random(1,#self.npcGenTypes)],
            self:getNPCGenPos(),
            self.npcGenCollCheck)
		tank:setAI(self.npcAI or self.defaultAI)
		self:setNetObj(tank)
	end
end

function mode:updateGameTime(dt)
    self.gameTimer = self.gameTimer - dt
    if self.gameTimer<0 then
        self:onTimeUp()
    end
end

function mode:addPlayer(player)
    self:setPlayerTeam(player)
    self:setPlayerTank(player)
end

function mode:setPlayerTeam(player)
    local min = 100
    local t = 1
    for i = 1,self.teamCount do
        local c = #self.teams[i]
        if c<min then
            t = i
            min = c
        end
    end
    player.team = t
    print(player.id .. " set to team "..t)
    table.insert(self.teams[t],player)
end

function mode:removePlayer(player)
    if not player then return end
    for i,p in ipairs(self.teams[player.team]) do
        if p == player then
            table.remove(self.teams[player.team],i)
        end
    end
    if player.tank and not player.tank.destroyed then 
        player.tank:destroy()
    end
end

function mode:getPlayerBirthPos(player) --被重写
    local pos = {
        minX = 1,
        maxX = self.map.w-1,
        minY = 1,
        maxY = self.map.h-1
        }
    return pos
end

function mode:setPlayerTank(player)
    local tank = self:newTank(
        player.team,
        self.playerGenTypes,
        self:getPlayerBirthPos(player),
        self.playerBirthCollCheck)
    tank.netID = player.id
    tank.player = player
    self:setNetObj(tank)
    player.tank = tank
    delay:new(0.2,function()
            net:sendToPlayer(player,"your_tank",{id = tank.id})
        end)
end
local colltag = {
    brick = true,
    iron = true,
    water = true,
    hq = true,
    tank = true,
    border = true
    }
local filter = function(other)
    return colltag[other.tag]
end
local filter_no_coll = function (other)
    return other.tag == "tank"
end

function mode:newTank(teams,types,pos,checkColl)
    local x,y
    local ix,iy
    while true do
        ix = math.random(pos.minX,pos.maxX)
        iy = math.random(pos.minY,pos.maxY)
        x = ix*16
        y = iy*16
        local colls,collCount = self.world:queryRect(x-16,y-16,32,32,
            checkColl and filter or filter_no_coll
        )
        if collCount == 0 then
            break
        end
    end
    if not checkColl then
        self.map:setTile(ix+1,iy,6)
        self.map:setTile(ix,iy,6)
        self.map:setTile(ix,iy+1,6)
        self.map:setTile(ix+1,iy+1,6)
    end
    
    local tank = Tank(
            self,
			x, --x
			y,  --y
			math.random(0,3), --rot
			2, --scale
			type(teams) == "number" and teams or teams[math.random(1,#teams)], --team
			type(types) == "number" and types or types[math.random(1,#types)]--type
        )
    return tank
end

function mode:onInit()
    
end

function mode:startGame()
    self.state = "run"
    net:sendToRoom(self.room,"game_start",{id = self.room.id})
    self:syncClock()
    print("game: "..self.room.id.." started")
end

function mode:onUpdate(dt)
    
end

function mode:onPlayerDead(player) --被重写
    
end

function mode:onTimeUp() --被重写
    self:gameOver()
end

function mode:gameOver(data)
    net:sendToRoom(self.room,"game_over", data or self:getScoreData())
    net:destroyRoom(self.room)
end

function mode:onKill(killer,victim)
    if victim.player then
        if self.enablePlayerRebirth then
            delay:new(self.playerRebirthCD,
                function() self:setPlayerTank(victim.player) end)
        else
            self:onPlayerDead(victim.player)
        end
    end
end

function mode:getScoreData()
    local data = {}
    for cid,player in pairs(self.players) do
        data[player.id] = player.score
    end
    return data
end

function mode:sendScoreData()
    net:sendToRoom(self.room,
        "your_score",
        self:getScoreData())
end

function mode:syncClock()
    self.room.gameTime = self.gameTimer
    net:sendToRoom(self.room,"sync_game_time",{time = self.gameTimer})
    if self.state == "run" then
        delay:new(0.5,function()
            self:syncClock()    
        end)
    end
end

return mode
